package com.jt.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import sun.misc.Request;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Bean//构建密码加密对象，登陆时，系统底层会基于此对象进行密码加密
    public BCryptPasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Bean
    public AuthenticationManager authenticationManagerBean()
            throws Exception {
        return super.authenticationManager();
    }
    /**
     * 假如在前后端分离架构中,希望对登录成功和失败以后的信息以json
     * 形式进行返回,我们自己控制哪些url需要认证,哪些不需要认证,
     * 我们可以重写下面的方法进行自定义
     * 说明：这个方法可以不写，默认跳转到index页面
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //super.configure(http);//默认所有请求都要认证
        //1.禁用跨域攻击(登录默认是post请求，但是跨域攻击不允许post请求)
        http.csrf().disable();
        //这种形式表示需要认证
//        http.authorizeRequests()
//              .mvcMatchers("/**").authenticated();
        //2.放行所有资源的访问(后续可以基于选择对资源进行认证和放行)
        http.authorizeRequests()
                .anyRequest().permitAll();//默认是放行的
//        http.authorizeRequests().anyRequest().authenticated();//不重写就是默认所有请求需要认证
//        http.authorizeRequests()
//                .anyRequest().permitAll()
//                .mvcMatchers("/order").authenticated();   表示只有订单服务需要认证
        //3.自定义定义登录成功和失败以后的处理逻辑(可选)
        //假如没有如下设置登录成功会显示404
        http.formLogin()//这句话会生成一个登录的路径/login
                .successHandler(successHandler())
                .failureHandler(failureHandler());
    }
    @Bean
    public AuthenticationSuccessHandler successHandler(){
        //lambda
        return (request,response,authentication)->{
            //构建map对象封装到要响应到客户端的数据
            Map<String,Object> map=new HashMap<>();
            map.put("state",200);
            map.put("message", "login ok");
            //将map对象转换为json格式字符串并写到客户端
            writeJsonToClient(response,map);
        };
    }
    @Bean
    public AuthenticationFailureHandler failureHandler(){
        return (request,response,exception)->{
            //构建map对象封装到要响应到客户端的数据
            Map<String,Object> map=new HashMap<>();
            map.put("state",500);
            map.put("message", "login error");
            //将map对象转换为json格式字符串并写到客户端
            writeJsonToClient(response,map);
        };
    }
    private void writeJsonToClient(
            HttpServletResponse response,
            Map<String,Object> map) throws IOException {
        //将map对象,转换为json
        String json=new ObjectMapper().writeValueAsString(map);
        //设置响应数据的编码方式
        response.setCharacterEncoding("utf-8");
        //设置响应数据的类型
        response.setContentType("application/json;charset=utf-8");
        //将数据响应到客户端
        PrintWriter out=response.getWriter();
        out.println(json);
        out.flush();
    }

}
